﻿//===============================================================================
// Magic OQL
//===============================================================================
// Copyright ?Magic Thought Corporation. All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// Richie (http://www.cnblogs.com/RicCC)
// March 5, 2008
//===============================================================================
// This class is ported from Antlr3.Runtime written by Kunle Odutola. (BaseTreeAdaptor & CommonTreeAdaptor)
//===============================================================================

using System;
using System.Collections.Generic;
using Antlr.Runtime;
using Antlr.Runtime.Tree;
using SQLAnalyticLibrary.Expressions;

namespace SQLAnalyticLibrary.Factory
{
    public class TreeFactory : BaseTreeAdaptor
    {
        private static IDictionary<int, IExpressionFactory> _factories;
        public int startIndex;
        public int stopIndex;
        protected IToken token;

        #region constructors
        /// <summary>
        /// Custom factories used to create OQL expressions.
        /// </summary>
        static TreeFactory()
        {
            //Using reflection can simply reduce code
            //Taking this approach not only for performance consideration, I just don't know what's I wanted and how to...
            //The process of building AST tree was moved to the inheritance hierarchy of Expression, and the AST
            //construction in grammar, this weaken the factory.
            //Maybe it will become usefull in coming days.
            _factories = new Dictionary<int, IExpressionFactory>();

            _factories.Add(OQLParser.UnionStmt, new UnionStatementFactory());
            _factories.Add(OQLParser.SelectStmt, new SelectStatementFactory());

            _factories.Add(OQLParser.SelectClause, new SelectClauseFactory());
            _factories.Add(OQLParser.FROM, new FromClauseFactory());
            _factories.Add(OQLParser.WhereClause, new WhereClauseFactory());
            _factories.Add(OQLParser.GroupByClause, new GroupByClauseFactory());
            _factories.Add(OQLParser.HAVING, new HavingFactory());
            _factories.Add(OQLParser.OrderByClause, new OrderByFactory());
            _factories.Add(OQLParser.OrderByItem, new OrderByItemFactory());

            _factories.Add(OQLParser.Alias, new AliasFactory());
            _factories.Add(OQLParser.Table, new TableFactory());
            _factories.Add(OQLParser.JoinedTable, new JoinedTableFactory());
            _factories.Add(OQLParser.Column, new ColumnFactory());

            _factories.Add(OQLParser.Predicate, new ComparisonFactory());
            _factories.Add(OQLParser.Predicate_Is, new IsFactory());
            _factories.Add(OQLParser.IN, new InFactory());
            _factories.Add(OQLParser.BETWEEN, new BetweenFactory());
            _factories.Add(OQLParser.EXISTS, new ExistsFactory());

            _factories.Add(OQLParser.ON, new OnFactory());
            _factories.Add(OQLParser.AND, new AndFactory());
            _factories.Add(OQLParser.OR, new OrFactory());
            _factories.Add(OQLParser.NOT, new NotFactory());
            _factories.Add(OQLParser.Group, new ConditionGroupFactory());

            _factories.Add(OQLParser.DataType, new DataTypeFactory());
            _factories.Add(OQLParser.TextNode, new TextFactory());

            _factories.Add(OQLParser.UserFunction, new FunctionFactory());
            //_factories.Add(OQLParser.CAST, new FunctionFactory());
            //_factories.Add(OQLParser.CONVERT, new FunctionFactory());
            _factories.Add(OQLParser.CASE, new FunctionFactory());
            _factories.Add(OQLParser.MIN, new FunctionFactory());
            _factories.Add(OQLParser.MAX, new FunctionFactory());
            _factories.Add(OQLParser.SUM, new FunctionFactory());
            _factories.Add(OQLParser.AVG, new FunctionFactory());
            _factories.Add(OQLParser.COUNT, new FunctionFactory());
            _factories.Add(OQLParser.LEN, new FunctionFactory());
        }

        public TreeFactory()
        {
        }
        public TreeFactory(IToken node)
        {
        }
        #endregion

        #region members for ITreeAdaptor


        public override object BecomeRoot(IToken newRoot, object oldRoot)
        {
            return this.BecomeRoot(this.Create(newRoot), oldRoot);
        }

        /// <summary>
        /// Create a null expression with given token: <paramref name="payLoad"/>.
        /// </summary>
        /// <param name="payload"></param>
        /// <returns></returns>
        public override object Create(IToken payload)
        {
            IExpressionFactory factory = null;
            Expression exp = null;
            if (payload == null) return new Expression(payload);
            if (_factories.TryGetValue(payload.Type, out factory))
                exp = factory.Create(payload);

            return exp != null ? exp : new Text(payload);
        }
        public override object Create(int tokenType, IToken fromToken)
        {
            fromToken = this.CreateToken(fromToken);
            fromToken.Type = tokenType;
            return (ITree)this.Create(fromToken);
        }

        public override object Create(int tokenType, string text)
        {
            IToken token = this.CreateToken(tokenType, text);
            return (ITree)this.Create(token);
        }

        public override object Create(int tokenType, IToken fromToken, string text)
        {
            fromToken = this.CreateToken(fromToken);
            fromToken.Type = tokenType;
            fromToken.Text = text;
            return (ITree)this.Create(fromToken);
        }

        /// <summary>
        /// Create a new copy of <paramref name="fromToken"/>
        /// </summary>
        /// <param name="fromToken"></param>
        /// <returns></returns>
        public override IToken CreateToken(IToken fromToken)
        {
            return new CommonToken(fromToken);
        }
        public override IToken CreateToken(int tokenType, string text)
        {
            return new CommonToken(tokenType, text);
        }
        public override object DupNode(object treeNode)
        {
            return ((ITree)treeNode).DupNode();
        }
        //public override object DupTree(object tree)
        //{
        //    return ((ITree)tree).DupTree();
        //}

      

        public virtual object GetNilNode()
        {
            return this.Create(null);
        }

        public virtual string GetNodeText(object t)
        {
            return ((ITree)t).Text;
        }

        public virtual int GetNodeType(object t)
        {
            return t != null && (t is ITree) ? (t as ITree).Type : 0;
        }

        public override IToken GetToken(object treeNode)
        {
            return (treeNode is Expression) ? (treeNode as Expression).Token : null;
        }
       
      
      
     

        public virtual void SetNodeText(object t, string text)
        {
            throw new NotImplementedException("don't know enough about Tree node");
        }

        public virtual void SetNodeType(object t, int type)
        {
            throw new NotImplementedException("don't know enough about Tree node");
        }

        //public virtual void SetTokenBoundaries(object t, IToken startToken, IToken stopToken)
        //{
        //    if (t == null) return;
        //    int tokenIndex = 0;
        //    int num2 = 0;
        //    if (startToken != null)
        //    {
        //        Antlr.Runtime.CommonToken token = startToken as Antlr.Runtime.CommonToken;
        //        if(token.StartIndex > startToken.TokenIndex)
        //            tokenIndex = token.StartIndex;
        //        else
        //            tokenIndex = startToken.TokenIndex;
        //    }
        //    if (stopToken != null)
        //    {
        //        Antlr.Runtime.CommonToken end = startToken as Antlr.Runtime.CommonToken;
        //        if (end.StartIndex > startToken.TokenIndex)
        //            num2 = end.StopIndex;
        //        else
        //            num2 = stopToken.TokenIndex;
        //    }
        //    ((ITree)t).TokenStartIndex = tokenIndex;
        //    ((ITree)t).TokenStopIndex = num2;
        //}
        #endregion

     
    }
}